﻿namespace Pub.Class
{
    using System;
    using System.Diagnostics;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Threading;

    public static class ActionExtensions
    {
        [DllImport("kernel32.dll")]
        private static extern IntPtr GetCurrentThread();
        private static ulong GetCycleCount()
        {
            ulong cycleTime = 0L;
            QueryThreadCycleTime(GetCurrentThread(), ref cycleTime);
            return cycleTime;
        }

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("kernel32.dll")]
        private static extern bool QueryThreadCycleTime(IntPtr threadHandle, ref ulong cycleTime);
        public static void Retry(this Action action, int numRetries, int retryTimeout, bool throwIfFail, Action<Exception> onFailureAction)
        {
            if (action.IsNull())
            {
                throw new ArgumentNullException("action");
            }
            numRetries--;
            do
            {
                bool flag = false;
                try
                {
                    action();
                    flag = true;
                }
                catch (Exception exception)
                {
                    flag = false;
                    if (onFailureAction.IsNotNull())
                    {
                        onFailureAction(exception);
                    }
                    if ((numRetries <= 0) && throwIfFail)
                    {
                        throw exception;
                    }
                }
                if ((retryTimeout > 0) && !flag)
                {
                    Thread.Sleep(retryTimeout);
                }
            }
            while (numRetries-- > 0);
        }

        public static string Time(this Action action, string name, int iteration)
        {
            if (string.IsNullOrEmpty(name))
            {
                return "";
            }
            StringBuilder builder = new StringBuilder();
            GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
            int[] numArray = new int[GC.MaxGeneration + 1];
            for (int i = 0; i <= GC.MaxGeneration; i++)
            {
                numArray[i] = GC.CollectionCount(i);
            }
            Stopwatch stopwatch = Stopwatch.StartNew();
            ulong cycleCount = GetCycleCount();
            for (int j = 0; j < iteration; j++)
            {
                action();
            }
            ulong num4 = GetCycleCount() - cycleCount;
            stopwatch.Stop();
            builder.AppendFormat("{0} 循环{1}次测试结果：<br />", name, iteration);
            builder.AppendFormat("使用时间：{0}ms<br />", stopwatch.ElapsedMilliseconds.ToString("N0"));
            builder.AppendFormat("CPU周期：{0}<br />", num4.ToString("N0"));
            for (int k = 0; k <= GC.MaxGeneration; k++)
            {
                builder.AppendFormat("Gen　　{0}：{1}<br />", k, GC.CollectionCount(k) - numArray[k]);
            }
            builder.Append("<br />");
            return builder.ToString();
        }
    }
}

